#include "internal.h"

/*
 * XXX: strictly: vd_i += N*r_i/w_i such that: vd_i > ve_i
 * this is probably good enough.
 */
static bool update_deadline(struct cfs_rq *cfs_rq, struct sched_entity *se)
{
    if ((s64)(se->vruntime - se->deadline) < 0)
        return false;

    /*
     * For EEVDF the virtual time slope is determined by w_i (iow.
     * nice) while the request time r_i is determined by
     * sysctl_sched_base_slice.
     */
    if (!se->custom_slice)
        se->slice = sysctl_sched_base_slice;

    /*
     * EEVDF: vd_i = ve_i + r_i / w_i
     */
    se->deadline = se->vruntime + calc_delta_fair(se->slice, se);

    /*
     * The task has consumed its request, reschedule.
     */
    return true;
}

static inline bool did_preempt_short(struct cfs_rq *cfs_rq, struct sched_entity *curr)
{
    return false; // TODO
}

/*
 * Update the current task's runtime statistics.
 */
static void update_curr(struct cfs_rq *cfs_rq)
{
    struct sched_entity *curr = cfs_rq->curr;
    struct rq *rq = rq_of(cfs_rq);
    s64 delta_exec;
    bool resched;

    if (unlikely(!curr))
        return;

    delta_exec = update_curr_se(rq, curr);
    if (unlikely(delta_exec <= 0))
        return;

    curr->vruntime += calc_delta_fair(delta_exec, curr);
    resched = update_deadline(cfs_rq, curr);
    update_min_vruntime(cfs_rq);

    if (entity_is_task(curr))
    {
        struct task_struct *p = task_of(curr);

        update_curr_task(p, delta_exec);

        /*
         * If the fair_server is active, we need to account for the
         * fair_server time whether or not the task is running on
         * behalf of fair_server or not:
         *  - If the task is running on behalf of fair_server, we need
         *    to limit its time based on the assigned runtime.
         *  - Fair task that runs outside of fair_server should account
         *    against fair_server such that it can account for this time
         *    and possibly avoid running this period.
         */
        if (dl_server_active(&rq->fair_server))
            ; // TODO dl_server_update(&rq->fair_server, delta_exec);
    }

    account_cfs_rq_runtime(cfs_rq, delta_exec);

    if (cfs_rq->nr_queued == 1)
        return;

    if (resched || did_preempt_short(cfs_rq, curr))
    {
        resched_curr_lazy(rq);
        clear_buddies(cfs_rq, curr);
    }
}

static void update_curr_fair(struct rq *rq)
{
    update_curr(cfs_rq_of(&rq->donor->se));
}
